﻿using Abp.Domain.Repositories;
using Abp.Domain.Services;
using Abp.Domain.Uow;
using Mt.Site.Core.Navigations.Entities;
using Mt.Site.Core.Navigations.Permissions;
using Mt.Site.Core.Synchronization.Data;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace Mt.Site.Core.Synchronization.Navigations
{
    public class MenuAutoSyncManager : DomainService, IMenuAutoSyncManager
    {
        private readonly IRepository<Menu, Guid> _menuRepository;
        private readonly IRepository<Bundling, Guid> _bundlingRepository;
        private readonly ISynchronizationHelper _synchronizationHelper;

        private readonly IMenuStore _menuStore;


        public MenuAutoSyncManager(
            ISynchronizationHelper synchronizationHelper,
            IRepository<Menu, Guid> menuRepository,
            IRepository<Bundling, Guid> bundlingRepository,
            IMenuStore menuStore)
        {
            _synchronizationHelper = synchronizationHelper;
            _menuRepository = menuRepository;
            _bundlingRepository = bundlingRepository;
            _menuStore = menuStore;
        }

        public async Task<Guid> DeleteMenuSync(MenuSyncArgs input)
        {
            using (CurrentUnitOfWork.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage,
                AbpDataFilters.SoftDelete))
            {
                var notify = new NoticeArgs();
                notify.MenuId = input.MenuId;
                try
                {
                    var fromEntity = _menuRepository.FirstOrDefault(input.Id);
                    if (fromEntity != null && fromEntity.IsDeleted)  //母站中的数据没有删除成功，子站中也不删
                    {
                        notify.FromId = fromEntity.Id;
                        notify.Title = fromEntity.DisplayName;
                        notify.ToLanguage = input.TargetLanguage;
                        notify.ToTenantId = input.ToTenantId;
                        notify.Type = input.OptionType;

                        var toEntity = _menuRepository.FirstOrDefault(
                            item => item.AuxiliaryId == fromEntity.AuxiliaryId && item.TenantId == input.ToTenantId);

                        if (toEntity != null)
                        {
                            if (_synchronizationHelper.ShouldSynchronize(toEntity))
                            {
                                notify.ToId = toEntity.Id;

                                await _menuStore.DeleteMenuItemAsync(toEntity, input.TargetLanguage);

                                await _synchronizationHelper.SendNoticeForSuccessAsync(
                                    notify,
                                    null,
                                    new List<string> { MenuPermissions.Pages_Tenant_Menus }
                                    );
                            }
                        }
                    }
                    return Guid.Empty;
                }
                catch (Exception)
                {
                    if (notify.FromId != Guid.Empty)
                    {
                        await _synchronizationHelper.SendNoticeForFailAsync(
                            notify,
                            null,
                            new List<string> { MenuPermissions.Pages_Tenant_Menus }
                            );
                    }
                    throw;
                }
            }
        }

        public async Task<Guid> UpdateMenuSync(MenuSyncArgs input)
        {
            using (CurrentUnitOfWork.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage,
                AbpDataFilters.SoftDelete))
            {
                var notify = new NoticeArgs();
                notify.MenuId = input.MenuId;
                try
                {
                    var syncInfoStore = await CheckMenuDataAndAutoSync(input.FromLanguage, input.TargetLanguage, input.ToTenantId, input.Id, notify);
                    notify.Type = input.OptionType;

                    if (syncInfoStore != null && syncInfoStore.ToId != Guid.Empty)
                    {
                        await _synchronizationHelper.SendNoticeForSuccessAsync(
                            notify,
                            null,
                            new List<string> { MenuPermissions.Pages_Tenant_Menus }
                            );
                        return syncInfoStore.ToId;
                    }
                }
                catch (Exception)
                {
                    if (notify.FromId != Guid.Empty)
                    {
                        await _synchronizationHelper.SendNoticeForFailAsync(
                            notify,
                            null,
                            new List<string> { MenuPermissions.Pages_Tenant_Menus }
                            );
                    }
                    throw;
                }
                return Guid.Empty;
            }
        }

        public async Task ResetMenuCacheAsync(int tenantId)
        {
            await _menuStore.ResetMenuCacheAsync(tenantId);
        }

        private async Task<AutoSyncInfoStore> CheckMenuDataAndAutoSync(string fromLanguage, string targetLanguage, int toTenantId, Guid fromId, NoticeArgs args)
        {
            var syncInfoStore = new AutoSyncInfoStore();
            var fromEntity = await _menuRepository.FirstOrDefaultAsync(fromId);
            if (fromEntity != null)
            {
                args.FromId = fromEntity.Id;
                args.Title = fromEntity.DisplayName;
                args.ToLanguage = targetLanguage;
                args.ToTenantId = toTenantId;

                var toEntity = await _menuRepository.FirstOrDefaultAsync(
                    item => item.AuxiliaryId == fromEntity.AuxiliaryId && item.TenantId == toTenantId);

                if (toEntity != null)
                {
                    syncInfoStore.IsAutoSync = _synchronizationHelper.ShouldSynchronize(toEntity);
                    if (syncInfoStore.IsAutoSync)
                    {
                        syncInfoStore.ToId = await _menuStore.UpdateMenuSync(toEntity, fromEntity);
                    }
                }

                if (syncInfoStore.ToId != Guid.Empty)
                {
                    // 同步路由
                    SyncRouteStr(fromEntity.Id, fromLanguage, syncInfoStore.ToId, toTenantId, targetLanguage);

                    args.ToId = syncInfoStore.ToId;
                    return syncInfoStore;
                }
            }

            return null;
        }

        public void SyncRouteStr(Guid fromId,string fromLanguageName, Guid toId, int toTenantId, string toLanguageName)
        {
            _synchronizationHelper.SyncRouteStr(fromId, fromLanguageName, toId, toTenantId, toLanguageName);
        }

        #region styles

        public async Task<Guid> ConfigSync(MenuSyncArgs input)
        {
            using (CurrentUnitOfWork.DisableFilter(
                AbpDataFilters.MayHaveTenant,
                AbpDataFilters.MustHaveTenant,
                MtSiteConsts.AbpDataFilters.MustHaveLanguage,
                AbpDataFilters.SoftDelete))
            {
                var notify = new NoticeArgs();
                notify.MenuId = input.MenuId;
                try
                {
                    var syncInfoStore = await CheckStylesAndAutoSync(input.TargetLanguage, input.ToTenantId, input.Id, notify);
                    notify.Type = input.OptionType;

                    if (syncInfoStore != null && syncInfoStore.ToId != Guid.Empty)
                    {
                        await _synchronizationHelper.SendNoticeForSuccessAsync(
                            notify,
                            null,
                            new List<string> { MenuPermissions.Pages_Tenant_Menus_StyleAndScript }
                            );

                        //返回栏目id
                        return syncInfoStore.ToId;
                    }
                }
                catch (Exception)
                {
                    if (notify.FromId != Guid.Empty)
                    {
                        await _synchronizationHelper.SendNoticeForFailAsync(
                            notify,
                            null,
                            new List<string> { MenuPermissions.Pages_Tenant_Menus_StyleAndScript }
                            );
                    }
                    throw;
                }
                return Guid.Empty;
            }
        }

        private async Task<AutoSyncInfoStore> CheckStylesAndAutoSync(string targetLanguage, int toTenantId, Guid fromMenuId, NoticeArgs args)
        {
            var fromMenuEntity = await _menuRepository.FirstOrDefaultAsync(fromMenuId);
            if (fromMenuEntity != null)
            {
                args.Title =  fromMenuEntity.DisplayName + "[Styles and Scripts]";
                args.ToLanguage = targetLanguage;
                args.ToTenantId = toTenantId;

                var toMenuEntity = await _menuRepository.FirstOrDefaultAsync(
                    item => item.AuxiliaryId == fromMenuEntity.AuxiliaryId && item.TenantId == toTenantId);

                //存在对应栏目
                if (toMenuEntity != null)
                {
                    var syncInfoStore = new AutoSyncInfoStore();
                    var toEntity = await _bundlingRepository.FirstOrDefaultAsync(c => c.MenuId == toMenuEntity.Id);
                    //是否接受自动同步
                    if(toEntity != null)
                    {
                        syncInfoStore.IsAutoSync = _synchronizationHelper.ShouldSynchronize(toEntity);
                    }
                    else
                    {
                        syncInfoStore.IsAutoSync = _synchronizationHelper.ShouldSynchronize(toMenuEntity);
                    }

                    if (syncInfoStore.IsAutoSync)
                    {
                        var fromEntity = await _bundlingRepository.FirstOrDefaultAsync(c => c.MenuId == fromMenuEntity.Id);
                        if(fromEntity != null)
                        {
                            args.FromId = fromEntity.Id;
                        }

                        var toEntityId = await _menuStore.StylesAndScriptsAutoSync(toEntity, fromEntity, toMenuEntity.Id, toMenuEntity.TenantId);
                        if (toEntityId != Guid.Empty)
                        {
                            args.ToId = toEntityId;

                            syncInfoStore.ToId = toMenuEntity.Id;
                            return syncInfoStore;
                        }
                    }
                }
            }

            return null;
        }
        #endregion
    }
}
